/*
** $Id: lstrlib.c $
** 标准字符串操作与模式匹配库
** 详见 lua.h 中的版权声明
*/

#define lstrlib_c
#define LUA_LIB

#include "lprefix.h"


#include <ctype.h>  /* 提供字符分类函数 */
#include <float.h>  /* 提供与浮点数相关的宏和常量 */
#include <limits.h>  /* 提供各种类型的最大值和最小值定义 */
#include <locale.h>  /* 提供本地化环境设置 */
#include <math.h>  /* 提供数学函数 */
#include <stddef.h>  /* 提供一些与内存大小相关的定义，如 size_t */
#include <stdio.h>  /* 提供输入输出函数 */
#include <stdlib.h>  /* 提供内存分配、数值转换等函数 */
#include <string.h>  /* 提供字符串操作函数 */

#include "lua.h"  /* Lua 核心函数 */

#include "lauxlib.h"  /* 辅助库，提供与 Lua 交互的 C 函数 */
#include "lualib.h"  /* Lua 标准库 */

/*
** 此文件包含了 Lua 标准字符串库的实现。它提供了各种字符串操作和模式匹配的功能，
** 包括但不限于：字符串连接、查找、替换、分割等。
*/

/*
** 定义模式匹配过程中可捕获的最大数量。
** 此限制是任意的，但必须适合在一个无符号字符中。
*/
#if !defined(LUA_MAXCAPTURES)
#define LUA_MAXCAPTURES		32  /* 默认最大捕获数为32 */
#endif

/*
** 定义一个宏，用于将字符转换为无符号字符。
*/
#define uchar(c)	((unsigned char)(c))

/*
** 限制某些大小以适应'int'，但同时必须适合'size_t'。
** 假设'lua_Integer'不会小于'int'。
*/
#define MAX_SIZET	((size_t)(~(size_t)0))
#define MAXSIZE \
    (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) /* 获取最大size_t值或int的最大值 */

/*
** 返回字符串的长度。
** @param L Lua状态机。
** @return 返回1，将字符串的长度作为Lua整数压入堆栈。
*/
static int str_len (lua_State *L) {
  size_t l;
  luaL_checklstring(L, 1, &l); /* 检查参数1是否为字符串并获取其长度 */
  lua_pushinteger(L, (lua_Integer)l); /* 将字符串长度压入Lua堆栈 */
  return 1; /* 表示函数执行完毕，返回1 */
}

/*
** 将相对初始字符串位置转换为绝对位置。
** 负值表示从末尾开始计算：结果限制在[1, +∞)范围内。
** Lua中的任何字符串长度都必须能容纳在一个lua_Integer中，
** 因此在转换过程中没有溢出。
** 使用倒置的比较可避免计算'-pos'时可能的溢出。
**
** @param pos 相对位置。
** @param len 字符串的长度。
** @return 转换后的绝对位置。
*/
static size_t posrelatI (lua_Integer pos, size_t len) {
  if (pos > 0)
    return (size_t)pos;
  else if (pos == 0)
    return 1; /* 如果pos为0，则认为是起始位置1 */
  else if (pos < -(lua_Integer)len)  /* 倒置比较避免溢出 */
    return 1;  /* 超出范围则限制为1 */
  else return len + (size_t)pos + 1; /* 计算绝对位置 */
}

/*
** 从参数中获取可选的结束字符串位置，如果没有提供则使用默认值。
** 负值表示从末尾开始计算：结果限制在[0, len]范围内。
**
** @param L Lua状态机。
** @param arg 参数索引。
** @param def 默认结束位置。
** @param len 字符串的长度。
** @return 返回计算后的结束位置。
*/
static size_t getendpos (lua_State *L, int arg, lua_Integer def,
                         size_t len) {
  lua_Integer pos = luaL_optinteger(L, arg, def); /* 获取可选的整数参数，如果没有则使用默认值 */
  if (pos > (lua_Integer)len)
    return len; /* 如果指定位置超过字符串长度，则返回字符串长度 */
  else if (pos >= 0)
    return (size_t)pos; /* 如果位置非负，则直接返回 */
  else if (pos < -(lua_Integer)len)
    return 0; /* 如果位置超出范围，则返回0 */
  else return len + (size_t)pos + 1; /* 计算并返回绝对位置 */
}

/*
 * 字符串子串函数
 * 从给定的字符串中提取子串，并将其推入Lua栈中。
 * 参数L是Lua状态机的指针。
 * 参数1是Lua栈中待处理的字符串。
 * 参数2是子串的开始位置。
 * 参数3是子串的结束位置。
 * 返回值是1，表示函数向Lua栈中推入了一个元素。
 */
static int str_sub (lua_State *L) {
  size_t l;
  const char *s = luaL_checklstring(L, 1, &l); // 检查并获取Lua栈中第一个参数为字符串的长度和指针。
  size_t start = posrelatI(luaL_checkinteger(L, 2), l); // 计算子串的起始绝对位置。
  size_t end = getendpos(L, 3, -1, l); // 计算子串的结束绝对位置。
  if (start <= end) // 如果起始位置小于等于结束位置，则提取子串。
    lua_pushlstring(L, s + start - 1, (end - start) + 1); // 将子串推入Lua栈。
  else lua_pushliteral(L, ""); // 如果起始位置大于结束位置，则推入空字符串。
  return 1;
}

/*
 * 字符串反转函数
 * 将Lua栈中第一个字符串参数反转后推入Lua栈。
 * 参数L是Lua状态机的指针。
 * 返回值是1，表示函数向Lua栈中推入了一个元素。
 */
static int str_reverse (lua_State *L) {
  size_t l, i;
  luaL_Buffer b;
  const char *s = luaL_checklstring(L, 1, &l); // 检查并获取Lua栈中第一个参数为字符串的长度和指针。
  char *p = luaL_buffinitsize(L, &b, l); // 初始化一个luaL_Buffer，用于存放反转后的字符串。
  for (i = 0; i < l; i++) // 遍历字符串，将其反转。
    p[i] = s[l - i - 1];
  luaL_pushresultsize(&b, l); // 将反转后的字符串推入Lua栈。
  return 1;
}

/*
 * 字符串转小写函数
 * 将Lua栈中第一个字符串参数的所有字符转换为小写后推入Lua栈。
 * 参数L是Lua状态机的指针。
 * 返回值是1，表示函数向Lua栈中推入了一个元素。
 */
static int str_lower (lua_State *L) {
  size_t l;
  size_t i;
  luaL_Buffer b;
  const char *s = luaL_checklstring(L, 1, &l); // 检查并获取Lua栈中第一个参数为字符串的长度和指针。
  char *p = luaL_buffinitsize(L, &b, l); // 初始化一个luaL_Buffer，用于存放转换后的字符串。
  for (i=0; i<l; i++) // 遍历字符串，将每个字符转换为小写。
    p[i] = tolower(uchar(s[i]));
  luaL_pushresultsize(&b, l); // 将转换后的字符串推入Lua栈。
  return 1;
}


/*
 * 将Lua栈顶的字符串全部转换为大写形式。
 *
 * 参数:
 *   L - Lua状态机指针。
 * 返回值:
 *   返回1，将转换后的字符串压入Lua栈。
 */
static int str_upper (lua_State *L) {
  size_t l;
  size_t i;
  luaL_Buffer b;
  const char *s = luaL_checklstring(L, 1, &l); // 检查Lua栈顶是否为字符串并获取其长度。
  char *p = luaL_buffinitsize(L, &b, l); // 初始化luaL_Buffer结构体，分配内存。
  for (i=0; i<l; i++)
    p[i] = toupper(uchar(s[i])); // 将字符串中的每个字符转换为大写。
  luaL_pushresultsize(&b, l); // 将转换后的字符串压入Lua栈。
  return 1;
}

/*
 * 在Lua栈顶的字符串重复n次，并可选择性地在每次重复之间插入分隔符。
 *
 * 参数:
 *   L - Lua状态机指针。
 * 返回值:
 *   返回1，将重复后的字符串压入Lua栈。
 */
static int str_rep (lua_State *L) {
  size_t l, lsep;
  const char *s = luaL_checklstring(L, 1, &l); // 检查并获取第一个参数（字符串）的长度。
  lua_Integer n = luaL_checkinteger(L, 2); // 检查并获取第二个参数（重复次数）。
  const char *sep = luaL_optlstring(L, 3, "", &lsep); // 获取可选的第三个参数（分隔符），若未提供则默认为空字符串。
  
  if (n <= 0)
    lua_pushliteral(L, ""); // 如果重复次数小于等于0，则直接返回空字符串。
  else if (l_unlikely(l + lsep < l || l + lsep > MAXSIZE / n))
    return luaL_error(L, "结果字符串太大resulting string too large"); // 检查结果字符串是否会超出最大允许大小。
  else {
    size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; // 计算结果字符串的总长度。
    luaL_Buffer b;
    char *p = luaL_buffinitsize(L, &b, totallen); // 初始化缓冲区用于构建结果字符串。
    
    while (n-- > 1) {  /* 先复制n-1次字符串，每次复制后跟上分隔符 */
      memcpy(p, s, l * sizeof(char)); p += l;
      if (lsep > 0) {  /* 如果分隔符非空，则复制分隔符 */
        memcpy(p, sep, lsep * sizeof(char));
        p += lsep;
      }
    }
    memcpy(p, s, l * sizeof(char));  /* 最后一次复制字符串，不跟随分隔符 */
    luaL_pushresultsize(&b, totallen); // 将构建好的字符串压入Lua栈。
  }
  return 1;
}

/*
 * 函数：str_byte
 * 功能：返回字符串中指定位置的字节。
 * 参数：
 *  - L: Lua状态机指针。
 *  - 1: 必需的字符串参数。
 *  - 2: 可选的起始位置参数，默认为1。
 * 返回值：返回压入Lua栈中的字节个数，或者在出错时返回0。
 */
static int str_byte (lua_State *L) {
  size_t l;
  const char *s = luaL_checklstring(L, 1, &l); // 检查并获取字符串参数及其长度。
  lua_Integer pi = luaL_optinteger(L, 2, 1); // 获取起始索引，默认为1。
  size_t posi = posrelatI(pi, l); // 调整起始位置，确保其在字符串长度范围内。
  size_t pose = getendpos(L, 3, pi, l); // 计算结束位置。
  int n, i;
  if (posi > pose) return 0;  /* 空区间；不返回任何值。 */
  if (l_unlikely(pose - posi >= (size_t)INT_MAX))  /* 检查是否会引起算术溢出。 */
    return luaL_error(L, "字符串切片太长string slice too long");
  n = (int)(pose -  posi) + 1; // 计算将要返回的字节个数。
  luaL_checkstack(L, n, "字符串切片太长string slice too long"); // 确保Lua栈空间足够。
  for (i=0; i<n; i++)
    lua_pushinteger(L, uchar(s[posi+i-1])); // 将每个字节作为整数压入Lua栈。
  return n;
}

/*
 * 函数：str_char
 * 功能：根据提供的整数参数创建一个包含这些字符的字符串。
 * 参数：
 *  - L: Lua状态机指针。
 * 返回值：返回压入Lua栈中的字符串个数，始终为1。
 */
static int str_char (lua_State *L) {
  int n = lua_gettop(L);  /* 获取Lua栈顶，即参数个数。 */
  int i;
  luaL_Buffer b;
  char *p = luaL_buffinitsize(L, &b, n); // 初始化缓冲区，初始大小为参数个数。
  for (i=1; i<=n; i++) { // 遍历所有参数。
    lua_Unsigned c = (lua_Unsigned)luaL_checkinteger(L, i); // 检查并获取整数参数。
    luaL_argcheck(L, c <= (lua_Unsigned)UCHAR_MAX, i, "值超出范围value out of range"); // 确保参数在有效范围内。
    p[i - 1] = uchar(c); // 将整数转换为字符，存储在缓冲区。
  }
  luaL_pushresultsize(&b, n); // 结束缓冲区构建，将字符串压入Lua栈。
  return 1;
}


/*
** 用于存储'string.dump'结果的缓冲区。必须在调用'lua_dump'之后初始化，
** 以确保调用'lua_dump'时函数位于栈顶。('luaL_buffinit'可能会推送一些内容。)
*/
struct str_Writer {
  int init;  /* 标记缓冲区是否已初始化 */
  luaL_Buffer B;
};


/*
** lua_State写入函数，用于收集编译后的函数二进制流。
**
** @param L       Lua状态机。
** @param b       要写入的数据块。
** @param size    数据块的大小。
** @param ud      用户数据，此处为struct str_Writer结构体的指针。
** @return        总是返回0。
*/
static int writer (lua_State *L, const void *b, size_t size, void *ud) {
  struct str_Writer *state = (struct str_Writer *)ud;
  if (!state->init) {
    state->init = 1;
    luaL_buffinit(L, &state->B);  /* 初始化Lua缓冲区 */
  }
  luaL_addlstring(&state->B, (const char *)b, size);  /* 将数据添加到缓冲区 */
  return 0;
}


/*
** 将Lua函数转换为二进制字节码字符串。
**
** @param L       Lua状态机。
** @return        成功时返回1，将二进制字节码作为字符串压入栈顶；失败时返回错误信息。
*/
static int str_dump (lua_State *L) {
  struct str_Writer state;
  int strip = lua_toboolean(L, 2);  /* 转换参数为strip标志，决定是否剥离调试信息 */
  luaL_checktype(L, 1, LUA_TFUNCTION);  /* 检查栈顶元素是否为函数 */
  lua_settop(L, 1);  /* 确保函数位于栈顶 */
  state.init = 0;
  /* 将函数编译成二进制流，并通过writer函数收集 */
  if (l_unlikely(lua_dump(L, writer, &state, strip) != 0))
    return luaL_error(L, "无法导出给定的函数unable to dump given function");  /* 如果出错，返回错误信息 */
  luaL_pushresult(&state.B);  /* 将收集到的二进制流作为字符串压入栈顶 */
  return 1;  /* 成功，返回1 */
}



/*
** {======================================================
** METAMETHODS元方法
** =======================================================
*/

#if defined(LUA_NOCVTS2N)	/* { */

/* 当定义了LUA_NOCVTS2N时，表示没有字符串到数字的强制转换 */

static const luaL_Reg stringmetamethods[] = {
  {"__index", NULL},  /* 占位符 */
  {NULL, NULL}
};

#else		/* }{ */

/* 尝试将参数转换为数字。如果已经是数字或者是可以转换为数字的字符串，则返回1。否则返回0。 */
static int tonum (lua_State *L, int arg) {
  if (lua_type(L, arg) == LUA_TNUMBER) {  /* 如果已经是数字？ */
    lua_pushvalue(L, arg);
    return 1;
  }
  else {  /* 检查是否是一个可以转换为数字的字符串 */
    size_t len;
    const char *s = lua_tolstring(L, arg, &len);
    return (s != NULL && lua_stringtonumber(L, s) == len + 1);
  }
}

/*
** 尝试使用元方法进行操作。如果操作数2是一个字符串或者没有对应的元方法，则抛出错误。
** 否则，将元方法插入到调用栈中，并执行该元方法。
*/
static void trymt (lua_State *L, const char *mtname) {
  lua_settop(L, 2);  /* 恢复到原始参数 */
  if (l_unlikely(lua_type(L, 2) == LUA_TSTRING ||
                 !luaL_getmetafield(L, 2, mtname)))
    luaL_error(L, "试图attempt to %s 操作a '%s' 当成with a '%s'", mtname + 2,
                  luaL_typename(L, -2), luaL_typename(L, -1));
  lua_insert(L, -3);  /* 将元方法放到参数之前 */
  lua_call(L, 2, 1);  /* 调用元方法 */
}

/*
** 执行两个操作数之间的算术操作。如果两个操作数都可以转换为数字，则直接执行算术操作。
** 否则，尝试调用对应的元方法。
** 返回1表示成功。
*/
static int arith (lua_State *L, int op, const char *mtname) {
  if (tonum(L, 1) && tonum(L, 2))
    lua_arith(L, op);  /* 结果将在栈顶 */
  else
    trymt(L, mtname);
  return 1;
}

/* 实现加法的元方法 */
static int arith_add (lua_State *L) {
  return arith(L, LUA_OPADD, "__add");
}

/* 实现减法的元方法 */
static int arith_sub (lua_State *L) {
  return arith(L, LUA_OPSUB, "__sub");
}

/* 实现乘法的元方法 */
static int arith_mul (lua_State *L) {
  return arith(L, LUA_OPMUL, "__mul");
}

/* 实现取模运算的元方法 */
static int arith_mod (lua_State *L) {
  return arith(L, LUA_OPMOD, "__mod");
}

/* 实现乘方的元方法 */
static int arith_pow (lua_State *L) {
  return arith(L, LUA_OPPOW, "__pow");
}

/* 实现除法的元方法 */
static int arith_div (lua_State *L) {
  return arith(L, LUA_OPDIV, "__div");
}

/* 实现整除的元方法 */
static int arith_idiv (lua_State *L) {
  return arith(L, LUA_OPIDIV, "__idiv");
}

/* 实现取反的元方法 */
static int arith_unm (lua_State *L) {
  return arith(L, LUA_OPUNM, "__unm");
}


/* 定义字符串的元方法列表 */
static const luaL_Reg stringmetamethods[] = {
  {"__add", arith_add},
  {"__加",arith_add},
  {"__sub", arith_sub},
  {"__减",arith_sub},
  {"__mul", arith_mul},
  {"__乘",arith_mul},
  {"__mod", arith_mod},
  {"__取模",arith_mod},
  {"__pow", arith_pow},
  {"__乘方",arith_pow},
  {"__div", arith_div},
  {"__整除",arith_div},
  {"__idiv", arith_idiv},
  {"__向下整除", arith_idiv},
  {"__unm", arith_unm},
  {"__负号", NULL},
  {"__index", NULL}, 
  {"__索引", NULL} ,/* 占位符 */
  {NULL, NULL}
};

#endif		/* } */		/* } */

/* }====================================================== */

/*
** {======================================================
** PATTERN MATCHING模式匹配
** =======================================================
*/

/* 定义匹配状态中特定的返回值和位置标识 */
#define CAP_UNFINISHED	(-1)  /* 表示匹配未完成 */
#define CAP_POSITION	(-2)  /* 表示匹配位置 */

/* 匹配状态的结构体定义 */
typedef struct MatchState {
  const char *src_init;  /* 源字符串的起始位置 */
  const char *src_end;  /* 源字符串的结束位置（'\0'） */
  const char *p_end;  /* 模式字符串的结束位置（'\0'） */
  lua_State *L;  /* 相关联的Lua状态机 */
  int matchdepth;  /* 递归深度控制，防止C栈溢出 */
  unsigned char level;  /* 已完成或未完成的捕获总数 */
  struct {
    const char *init;  /* 捕获内容的起始位置 */
    ptrdiff_t len;  /* 捕获内容的长度 */
  } capture[LUA_MAXCAPTURES];  /* 捕获内容的数组，最多支持LUA_MAXCAPTURES个捕获 */
} MatchState;

/*
 * 递归函数
 * 
 * 功能：根据模式字符串p在文本字符串s中寻找匹配。
 * 参数：
 *    - ms: 匹配状态结构体指针，存储匹配过程中的状态信息。
 *    - s: 待匹配的文本字符串。
 *    - p: 模式字符串。
 * 返回值：如果匹配成功，返回匹配结束的位置指针；如果匹配失败，返回NULL。
 */
static const char *match (MatchState *ms, const char *s, const char *p);


/*
 * 定义'match'函数的最大递归深度
 * 
 * 如果未定义MAXCCALLS，则默认设置为200。
 */
#if !defined(MAXCCALLS)
#define MAXCCALLS	200
#endif


/*
 * 定义一些常用的常量
 */
#define L_ESC		'%'
#define SPECIALS	"^$*+?.([%-"


/*
 * 检查给定的捕获索引是否有效
 * @param ms 匹配状态结构体，包含匹配过程中的各种状态信息
 * @param l 捕获索引，以字符'1'开始递增
 * @return 有效的捕获索引，如果索引无效则抛出Lua错误
 */
static int check_capture (MatchState *ms, int l) {
  l -= '1'; /* 将字符索引转换为数组索引 */
  if (l_unlikely(l < 0 || l >= ms->level ||
                 ms->capture[l].len == CAP_UNFINISHED))
    return luaL_error(ms->L, "无效的捕获索引invalid capture index %%%d", l + 1); /* 抛出无效捕获索引错误 */
  return l; /* 返回调整后的捕获索引 */
}


/*
 * 查找最近未关闭的捕获括号的索引
 * @param ms 匹配状态结构体
 * @return 最近未关闭的捕获括号的索引，如果找不到则抛出Lua错误
 */
static int capture_to_close (MatchState *ms) {
  int level = ms->level;
  for (level--; level>=0; level--)
    if (ms->capture[level].len == CAP_UNFINISHED) return level; /* 找到未完成的捕获 */
  return luaL_error(ms->L, "无效的模式捕获invalid pattern capture"); /* 如果没有未完成的捕获，则抛出错误 */
}


/*
 * 根据当前匹配位置和模式字符串，确定下一个字符类的结束位置
 * @param ms 匹配状态结构体
 * @param p 当前模式字符串的指针
 * @return 字符类的结束位置指针
 */
static const char *classend (MatchState *ms, const char *p) {
  switch (*p++) { /* 根据当前字符采取不同的处理 */
    case L_ESC: { /* 如果遇到转义字符 */
      if (l_unlikely(p == ms->p_end))
        luaL_error(ms->L, "格式错误的模式malformed pattern (ends with '%%' 结束)"); /* 检查模式字符串是否结束 */
      return p+1; /* 返回转义字符后的位置 */
    }
    case '[': { /* 如果遇到字符类起始符 */
      if (*p == '^') p++; /* 如果是负向字符类，则跳过'^' */
      do {  /* 循环查找']' */
        if (l_unlikely(p == ms->p_end))
          luaL_error(ms->L, "malformed pattern格式错误的模式 (missing缺少 ']')"); /* 检查模式字符串是否结束或缺失']' */
        if (*(p++) == L_ESC && p < ms->p_end)
          p++;  /* 跳过转义序列（例如'%]'） */
      } while (*p != ']');
      return p+1; /* 返回字符类结束位置之后 */
    }
    default: { /* 默认情况下直接返回当前位置 */
      return p;
    }
  }
}
/**
 * 根据指定的类别检查字符是否匹配。
 * 
 * @param c 待检查的字符。
 * @param cl 指定的字符类别，使用小写字母表示不同的字符属性。
 * @return 如果字符c匹配指定的类别cl，则返回1；否则，返回0。
 */
static int match_class (int c, int cl) {
  int res;
  switch (tolower(cl)) { // 将类别参数转换为小写字母进行匹配
    case 'a' : res = isalpha(c); break; // 检查字符是否为字母
    case 'c' : res = iscntrl(c); break; // 检查字符是否为控制字符
    case 'd' : res = isdigit(c); break; // 检查字符是否为数字
    case 'g' : res = isgraph(c); break; // 检查字符是否为可打印的图形字符
    case 'l' : res = islower(c); break; // 检查字符是否为小写字母
    case 'p' : res = ispunct(c); break; // 检查字符是否为标点符号
    case 's' : res = isspace(c); break; // 检查字符是否为空白字符（包括空格、制表符等）
    case 'u' : res = isupper(c); break; // 检查字符是否为大写字母
    case 'w' : res = isalnum(c); break; // 检查字符是否为字母或数字
    case 'x' : res = isxdigit(c); break; // 检查字符是否为十六进制数字
    case 'z' : res = (c == 0); break;  /* deprecated option */ // 已弃用的选项，检查字符是否为零
    default: return (cl == c); // 如果没有匹配到任何类别，直接检查字符是否相等
  }
  return (islower(cl) ? res : !res); // 如果指定的类别是小写字母，则返回结果；否则，返回结果的反义
}


/*
 * 验证给定字符是否属于指定的括号类别。
 * 
 * 参数:
 *   c - 需要验证的字符。
 *   p - 指向括号类别的字符串起始位置的指针。
 *   ec - 指向括号类别字符串的结束位置的指针。
 * 
 * 返回值:
 *   如果字符c匹配括号类别，则返回1；如果不匹配，则返回0。
 */
static int matchbracketclass (int c, const char *p, const char *ec) {
  int sig = 1;  // 初始标志，设定为1表示匹配，除非遇到'^'。
  if (*(p+1) == '^') {
    sig = 0;  // 如果类别以'^'开头，则表示不匹配。
    p++;  /* 跳过'^'字符 */
  }
  while (++p < ec) {  // 遍历括号类别字符串。
    if (*p == L_ESC) {  // 处理转义字符。
      p++;
      if (match_class(c, uchar(*p)))
        return sig;  // 如果字符c匹配转义后的字符类，则返回当前的sig值。
    }
    else if ((*(p+1) == '-') && (p+2 < ec)) {  // 处理范围字符。
      p+=2;
      if (uchar(*(p-2)) <= c && c <= uchar(*p))
        return sig;  // 如果字符c在范围内，则返回当前的sig值。
    }
    else if (uchar(*p) == c) return sig;  // 如果字符c直接匹配，则返回当前的sig值。
  }
  return !sig;  // 如果遍历结束还未返回，则根据初始的sig值决定最终返回值。
}


/**
 * 根据模式串p中的当前字符，检查文本串s中的当前字符是否匹配。
 * @param ms 匹配状态结构体，包含匹配过程中的各种状态和信息。
 * @param s 文本串的当前指针位置。
 * @param p 模式串的当前指针位置。
 * @param ep 模式串的结束位置指针。
 * @return 如果匹配成功返回1，如果s已经超出其范围返回0，否则根据模式串当前字符的具体类型返回相应的值。
 */
static int singlematch (MatchState *ms, const char *s, const char *p,
                        const char *ep) {
  // 检查文本串s是否已经遍历完毕
  if (s >= ms->src_end)
    return 0;
  else {
    int c = uchar(*s); // 将文本串当前字符转换为无符号字符
    switch (*p) { // 根据模式串当前字符的类型进行匹配检查
      case '.': return 1;  /* 匹配任何字符 */
      case L_ESC: return match_class(c, uchar(*(p+1))); // 匹配字符类别
      case '[': return matchbracketclass(c, p, ep-1); // 匹配括号类
      default:  return (uchar(*p) == c); // 直接比较字符是否相等
    }
  }
}

/*
 * 作用：匹配字符串s中与模式p对应的平衡字符组。
 * 参数：
 *   ms - 匹配状态结构体，包含匹配所需的额外状态。
 *   s - 被匹配的字符串的起始位置。
 *   p - 模式字符串的起始位置。
 * 返回值：
 *   如果找到平衡的字符组，返回匹配结束后的字符串位置；否则返回NULL。
 */

static const char *matchbalance (MatchState *ms, const char *s,
                                   const char *p) {
  // 检查模式字符串是否结束，防止未定义行为，若结束则抛出错误
  if (l_unlikely(p >= ms->p_end - 1))
    luaL_error(ms->L, "malformed pattern格式错误的模式 (missing arguments to缺少参数 '%%b')");
  // 检查被匹配字符串和模式字符串的起始字符是否匹配，不匹配直接返回NULL
  if (*s != *p) return NULL;
  else {
    // 定义开始和结束平衡字符
    int b = *p;
    int e = *(p+1);
    // 记录当前嵌套层级的计数器
    int cont = 1;
    // 遍历字符串s，寻找平衡的字符组
    while (++s < ms->src_end) {
      // 如果遇到结束字符，减少嵌套层级计数器
      if (*s == e) {
        if (--cont == 0) return s+1;  // 如果计数器为0，表示找到平衡，返回结束位置后一个位置
      }
      // 如果遇到开始字符，增加嵌套层级计数器
      else if (*s == b) cont++;
    }
  }
  // 字符串结束时，如果计数器不为0，表示没有找到平衡，返回NULL
  return NULL;  
}


/**
 * 尝试在给定字符串s中，根据模式p的最大扩展次数找到匹配。
 * 
 * @param ms 匹配状态结构体，用于记录匹配过程中的状态。
 * @param s 待匹配的字符串起始位置。
 * @param p 模式字符串的起始位置。
 * @param ep 模式字符串的结束位置。
 * @return 如果找到匹配，则返回匹配成功后的字符串位置；否则返回NULL。
 */
static const char *max_expand (MatchState *ms, const char *s,
                                 const char *p, const char *ep) {
  ptrdiff_t i = 0;  /* 用于计算项目最大扩展次数的计数器 */
  /* 尝试匹配模式p在字符串s上的最大扩展次数 */
  while (singlematch(ms, s + i, p, ep))
    i++;
    
  /* 持续尝试使用最大重复次数进行匹配 */
  while (i>=0) {
    const char *res = match(ms, (s+i), ep+1);
    if (res) return res;  /* 如果匹配成功，则返回匹配结果 */
    i--;  /* 如果未匹配，则减少一次重复尝试再次匹配 */
  }
  return NULL; /* 如果无法找到匹配，则返回NULL */
}


/**
 * 尝试匹配字符串s中以p为模式的最小扩展。
 * 
 * @param ms 匹配状态结构体，存储匹配过程中的状态信息。
 * @param s 待匹配的字符串起始位置。
 * @param p 模式字符串的起始位置。
 * @param ep 模式字符串的结束位置。
 * @return 如果匹配成功，返回匹配的结束位置；如果无法匹配，返回NULL。
 */
static const char *min_expand (MatchState *ms, const char *s,
                                 const char *p, const char *ep) {
  for (;;) { // 无限循环，尝试各种可能的匹配
    const char *res = match(ms, s, ep+1); // 尝试匹配模式字符串p到ep+1位置的子串
    if (res != NULL)
      return res; // 如果匹配成功，返回匹配的结束位置
    else if (singlematch(ms, s, p, ep)) // 如果p到ep位置的子串可以匹配
      s++;  /* 尝试下一个字符进行匹配，即增加匹配的长度 */
    else return NULL; // 如果无法匹配，则返回NULL
  }
}

/**
 * 开始一次捕获操作。
 * 
 * @param ms 匹配状态结构体，存储匹配过程中的状态信息。
 * @param s 指向待匹配字符串的起始位置的指针。
 * @param p 指向正则表达式的指针。
 * @param what 指定捕获的类型或长度。
 * @return 如果匹配成功，返回匹配结束的位置；如果匹配失败，返回NULL。
 * 
 * 该函数用于开始一次捕获操作，初始化捕获的起始位置和长度，并执行匹配。
 * 如果捕获层数超过预定义的最大值，将抛出错误。
 * 如果匹配失败，会回退捕获层数，撤销此次捕获。
 */
static const char *start_capture (MatchState *ms, const char *s,
                                    const char *p, int what) {
  const char *res;
  int level = ms->level;  // 获取当前捕获层级
  
  // 检查捕获层数是否超过最大值
  if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "捕获过多too many captures");
  
  // 初始化捕获的起始位置和长度
  ms->capture[level].init = s;
  ms->capture[level].len = what;
  
  // 更新捕获层数
  ms->level = level+1;
  
  // 尝试进行匹配
  if ((res=match(ms, s, p)) == NULL)  /* match failed? */
    ms->level--;  /* undo capture */  // 如果匹配失败，回退捕获层数
  
  return res;
}


/**
 * 结束一次捕获，并根据匹配结果更新捕获信息。
 * 
 * @param ms 匹配状态结构体，存储着匹配过程中的各种状态和捕获信息。
 * @param s 当前匹配的字符串位置。
 * @param p 正则表达式模式。
 * @return 如果匹配成功，则返回匹配结束的位置；如果匹配失败，则返回NULL。
 */
static const char *end_capture (MatchState *ms, const char *s,
                                  const char *p) {
  int l = capture_to_close(ms);  // 找到需要关闭的最深的捕获组
  const char *res;
  ms->capture[l].len = s - ms->capture[l].init;  /* 更新捕获组的长度，表示捕获的字符串长度 */

  // 尝试在当前位置s开始匹配模式p，如果匹配失败，则将刚才的捕获组长度设为未完成状态
  if ((res = match(ms, s, p)) == NULL)  
    ms->capture[l].len = CAP_UNFINISHED;  

  return res;  // 返回匹配结果
}

/**
 * 根据给定的匹配状态、字符串和索引，查找并返回匹配的字符串的结束位置。
 * 
 * @param ms 匹配状态结构体，包含匹配的相关信息和状态。
 * @param s 被搜索的字符串。
 * @param l 索引，指定要查找的捕获组。
 * @return 如果找到匹配的字符串，返回匹配结束的位置；如果没有找到，返回NULL。
 */
static const char *match_capture (MatchState *ms, const char *s, int l) {
  size_t len;
  // 检查捕获组索引的有效性，并更新索引l为实际的捕获组编号
  l = check_capture(ms, l);
  // 获取指定捕获组的长度
  len = ms->capture[l].len;
  // 检查当前位置到字符串末尾的长度是否大于等于捕获组长度，并且内容是否匹配
  if ((size_t)(ms->src_end-s) >= len &&
      memcmp(ms->capture[l].init, s, len) == 0)
    return s+len; // 如果匹配成功，返回匹配结束的位置
  else return NULL; // 如果匹配失败，返回NULL
}


/*
 * 在给定的字符串s中，根据模式p搜索匹配的子字符串。
 * 
 * 参数:
 *   - ms: 匹配状态结构体，包含匹配过程中的状态和环境。
 *   - s: 源字符串的起始位置。
 *   - p: 模式字符串的当前位置。
 * 
 * 返回值:
 *   - 如果找到匹配的子字符串，则返回匹配后的源字符串位置。
 *   - 如果没有找到匹配的子字符串，则返回NULL。
 */

static const char *match (MatchState *ms, const char *s, const char *p) {
  // 检查匹配深度，防止无限递归
  if (l_unlikely(ms->matchdepth-- == 0))
    luaL_error(ms->L, "模式过于复杂pattern too complex");
  
  init: /* 使用goto优化尾递归 */
  // 当模式未结束时
  if (p != ms->p_end) {  
    switch (*p) {
      case '(': {  /* 开始捕获 */
        if (*(p + 1) == ')')  /* 位置捕获？ */
          s = start_capture(ms, s, p + 2, CAP_POSITION);
        else
          s = start_capture(ms, s, p + 1, CAP_UNFINISHED);
        break;
      }
      case ')': {  /* 结束捕获 */
        s = end_capture(ms, s, p + 1);
        break;
      }
      case '$': {
        if ((p + 1) != ms->p_end)  /* '$'是否为模式的最后一个字符？ */
          goto dflt;  /* 不是，则进行默认处理 */
        s = (s == ms->src_end) ? s : NULL;  /* 检查字符串末尾 */
        break;
      }
      case L_ESC: {  /* 转义序列 */
        switch (*(p + 1)) {
          case 'b': {  /* 平衡字符串匹配 */
            s = matchbalance(ms, s, p + 2);
            if (s != NULL) {
              p += 4; goto init;  /* 成功匹配，继续匹配下一个 */
            }  
            break;
          }
          case 'f': {  /* 前沿匹配 */
            const char *ep; char previous;
            p += 2;
            if (l_unlikely(*p != '['))
              luaL_error(ms->L, "missing模式中缺少 '[' after在 '%%f' 后in pattern");
            ep = classend(ms, p);  /* 找到下一个标志位 */
            previous = (s == ms->src_init) ? '\0' : *(s - 1);
            if (!matchbracketclass(uchar(previous), p, ep - 1) &&
               matchbracketclass(uchar(*s), p, ep - 1)) {
              p = ep; goto init;  /* 成功匹配，继续匹配下一个 */
            }
            s = NULL;  /* 匹配失败 */
            break;
          }
          case '0': case '1': case '2': case '3':
          case '4': case '5': case '6': case '7':
          case '8': case '9': {  /* 捕获结果匹配 */
            s = match_capture(ms, s, uchar(*(p + 1)));
            if (s != NULL) {
              p += 2; goto init;  /* 成功匹配，继续匹配下一个 */
            }
            break;
          }
          default: goto dflt;
        }
        break;
      }
      default: dflt: {  /* 模式类别和可选后缀 */
        const char *ep = classend(ms, p);  /* 指向可选后缀 */
        /* 至少不能匹配一次？ */
        if (!singlematch(ms, s, p, ep)) {
          if (*ep == '*' || *ep == '?' || *ep == '-') {  /* 接受空字符串？ */
            p = ep + 1; goto init;  /* 继续匹配下一个 */
          }
          else  /* '+' 或没有后缀 */
            s = NULL;  /* 匹配失败 */
        }
        else {  /* 匹配了一次 */
          switch (*ep) {  /* 处理可选后缀 */
            case '?': {  /* 可选 */
              const char *res;
              if ((res = match(ms, s + 1, ep + 1)) != NULL)
                s = res;
              else {
                p = ep + 1; goto init;  /* 否则继续匹配下一个 */
              }
              break;
            }
            case '+':  /* 1次或更多重复 */
              s++;  /* 已经匹配1次 */
              /* FALLTHROUGH */
            case '*':  /* 0次或更多重复 */
              s = max_expand(ms, s, p, ep);
              break;
            case '-':  /* 0次或更多重复（最小值） */
              s = min_expand(ms, s, p, ep);
              break;
            default:  /* 没有后缀 */
              s++; p = ep; goto init;  /* 继续匹配下一个 */
          }
        }
        break;
      }
    }
  }
  ms->matchdepth++;
  return s;
}


/**
 * 在指定的字符串s1中查找字符串s2。
 * 
 * @param s1 指向要搜索的字符串的指针。
 * @param l1 s1字符串的长度。
 * @param s2 指向要查找的子字符串的指针。
 * @param l2 s2字符串的长度。
 * @return 如果找到s2，则返回s2在s1中的位置指针；如果未找到，返回NULL。
 */
static const char *lmemfind (const char *s1, size_t l1,
                               const char *s2, size_t l2) {
  // 处理空字符串的情况：如果s2为空，则认为s2存在于s1的起始位置。
  if (l2 == 0) return s1;  
  // 如果s2的长度大于s1的长度，直接返回NULL，因为无法在s1中找到s2。
  else if (l2 > l1) return NULL;  
  else {
    const char *init;  // 用于在s1中搜索s2。
    l2--;  // 将l2减1，因为memchr将检查第一个字符。
    l1 = l1-l2;  // 调整l1的值，s2不可能出现在s1的这个位置之后。
    // 当l1大于0且s1中存在s2的首字符时循环。
    while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
      init++;   // 跳过已经检查的首字符。
      // 如果init指向的字符串与s2剩余部分匹配，则返回init的前一个位置。
      if (memcmp(init, s2+1, l2) == 0)
        return init-1;
      else {  // 如果不匹配，调整l1和s1的位置，继续尝试。
        l1 -= init-s1;
        s1 = init;
      }
    }
    return NULL;  // 如果未找到s2，返回NULL。
  }
}


/*
** 获取第i个捕获的信息。如果没有捕获，且'i==0'，则返回整个匹配的范围's'..'e'的信息。
** 如果捕获是字符串，则返回其长度并将它的地址赋给'*cap'。如果捕获是整数（一个位置），
** 则将其压入栈中并返回CAP_POSITION。
**
** 参数:
** - ms: 匹配状态指针，包含匹配的相关信息。
** - i: 捕获的索引。
** - s: 匹配的起始位置。
** - e: 匹配的结束位置。
** - cap: 指向捕获内容地址的指针。
**
** 返回值:
** - 返回捕获的长度。如果是位置捕获，则返回CAP_POSITION。
*/
static size_t get_onecapture (MatchState *ms, int i, const char *s,
                              const char *e, const char **cap) {
  if (i >= ms->level) { // 当索引i大于等于捕获层级时，处理整个匹配范围的情况
    if (l_unlikely(i != 0))
      luaL_error(ms->L, "invalid capture index无效的捕获索引 %%%d", i + 1); // 如果i不为0，报告无效的捕获索引
    *cap = s; // 设置捕获内容的起始位置
    return e - s; // 返回匹配的长度
  }
  else { // 处理具体捕获的情况
    ptrdiff_t capl = ms->capture[i].len; // 获取捕获的长度
    *cap = ms->capture[i].init; // 设置捕获内容的起始位置
    if (l_unlikely(capl == CAP_UNFINISHED))
      luaL_error(ms->L, "捕获未完成unfinished capture"); // 如果捕获未完成，报告错误
    else if (capl == CAP_POSITION)
      lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); // 如果捕获是位置，将其压入Lua栈
    return capl; // 返回捕获的长度
  }
}


/*
** 将第 i 个捕获结果压入栈中。
**
** 参数:
** - ms: 匹配状态结构体，存储了匹配过程中的各种状态和信息。
** - i: 指定要压入栈中的捕获结果的索引。
** - s: 捕获的起始位置指针。
** - e: 捕获的结束位置指针。
*/
static void push_onecapture (MatchState *ms, int i, const char *s,
                                                    const char *e) {
  const char *cap;
  // 获取第 i 个捕获的结果，返回结果的长度。如果捕获的是位置，则返回 CAP_POSITION。
  ptrdiff_t l = get_onecapture(ms, i, s, e, &cap);
  // 如果捕获的不是位置，则将捕获结果压入 Lua 栈。
  if (l != CAP_POSITION)
    lua_pushlstring(ms->L, cap, l);
  /* else position was already pushed */
  // 如果捕获的是位置，之前已经将其压入了栈中，这里就不需要重复操作了。
}

/*
 * 将匹配到的捕获内容推入Lua栈中。
 * 
 * @param ms 匹配状态结构体，包含匹配的相关信息。
 * @param s 捕获内容的起始位置指针。
 * @param e 捕获内容的结束位置指针。
 * @return 返回推入Lua栈中的字符串数量。
 */
static int push_captures (MatchState *ms, const char *s, const char *e) {
  int i;
  int nlevels = (ms->level == 0 && s) ? 1 : ms->level; // 计算需要推入栈中的捕获层级数量
  luaL_checkstack(ms->L, nlevels, "捕获过多too many captures"); // 检查Lua栈是否足够存放所有捕获内容，不足则抛出异常
  for (i = 0; i < nlevels; i++)
    push_onecapture(ms, i, s, e); // 逐个将捕获内容推入Lua栈
  return nlevels;  /* 返回推入Lua栈中的字符串数量 */
}

/*
 * 检查模式串中是否没有特殊字符
 * 
 * 参数：
 *   p - 指向要检查的模式串的指针。
 *   l - 模式串的长度。
 * 
 * 返回值：
 *   如果模式串中没有特殊字符，则返回1。
 *   如果模式串中包含特殊字符，则返回0。
 */
static int nospecials (const char *p, size_t l) {
  size_t upto = 0; // 初始化检查进度为0
  do {
    // 如果在当前检查位置发现特殊字符，则返回0
    if (strpbrk(p + upto, SPECIALS))
      return 0;  
    // 更新检查位置到下一个字符串的起始位置
    upto += strlen(p + upto) + 1;  
  } while (upto <= l); // 继续检查直到遍历完所有字符或找到特殊字符
  return 1;  /* 没有发现特殊字符，返回1 */
}

/*
 * 准备MatchState结构体的状态
 *
 * 参数:
 *   ms - 指向MatchState结构体的指针，是匹配状态的容器
 *   L - 指向当前lua_State的指针，用于保存Lua环境的状态
 *   s - 源字符串的起始指针
 *   ls - 源字符串的长度
 *   p - 正则表达式的指针
 *   lp - 正则表达式的长度
 */
static void prepstate (MatchState *ms, lua_State *L,
                       const char *s, size_t ls, const char *p, size_t lp) {
  ms->L = L;          // 将lua_State指针保存到MatchState中
  ms->matchdepth = MAXCCALLS; // 设置递归调用的最大深度
  ms->src_init = s;   // 设置源字符串的起始位置
  ms->src_end = s + ls; // 设置源字符串的结束位置
  ms->p_end = p + lp;  // 设置正则表达式的结束位置
}

/*
 * 重新准备MatchState结构体的状态，重置级别和检查匹配深度
 *
 * 参数:
 *   ms - 指向MatchState结构体的指针
 *
 * 注: 此函数假设MatchState的matchdepth初始值为MAXCCALLS。
 */
static void reprepstate (MatchState *ms) {
  ms->level = 0;      // 重置嵌套级别的计数
  lua_assert(ms->matchdepth == MAXCCALLS); // 断言匹配深度是否为初始值，确保状态正确
}


/*
 * 辅助字符串查找函数
 * 
 * L: Lua状态机指针，用于操作Lua栈和调用Lua库函数。
 * find: 一个标志变量，决定是查找操作还是替换操作。
 * 
 * 返回值: 执行成功返回1或2，失败返回1，并将错误信息压入Lua栈。
 */

static int str_find_aux (lua_State *L, int find) {
  size_t ls, lp; // ls为被搜索字符串的长度，lp为模式字符串的长度
  const char *s = luaL_checklstring(L, 1, &ls); // 检查并获取第一个参数（被搜索字符串）
  const char *p = luaL_checklstring(L, 2, &lp); // 检查并获取第二个参数（模式字符串）
  size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; // 计算搜索的起始位置
  if (init > ls) {  /* 起始位置在字符串之后？ */
    luaL_pushfail(L);  /* 无法找到任何匹配 */
    return 1;
  }
  /* 如果是查找操作，且没有特殊字符或显式要求普通搜索 */
  if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) {
    /* 执行普通字符串查找 */
    const char *s2 = lmemfind(s + init, ls - init, p, lp);
    if (s2) {
      lua_pushinteger(L, (s2 - s) + 1); // 匹配起始位置
      lua_pushinteger(L, (s2 - s) + lp); // 匹配结束位置
      return 2;
    }
  }
  else {
    MatchState ms; // 定义匹配状态结构体
    const char *s1 = s + init; // 设置搜索起始点
    int anchor = (*p == '^'); // 检查模式字符串是否以锚点开始
    if (anchor) {
      p++; lp--;  /* 跳过锚点字符 */
    }
    prepstate(&ms, L, s, ls, p, lp); // 准备匹配状态
    do {
      const char *res;
      reprepstate(&ms); // 重新准备匹配状态
      if ((res=match(&ms, s1, p)) != NULL) { // 执行匹配
        if (find) {
          lua_pushinteger(L, (s1 - s) + 1);  /* 匹配起始位置 */
          lua_pushinteger(L, res - s);   /* 匹配结束位置 */
          return push_captures(&ms, NULL, 0) + 2; // 推入捕获结果并返回
        }
        else
          return push_captures(&ms, s1, res); // 推入捕获结果并返回
      }
    } while (s1++ < ms.src_end && !anchor); // 按条件循环搜索
  }
  luaL_pushfail(L);  /* 未找到匹配 */
  return 1;
}


/* 
 * 查找字符串中指定模式的第一个匹配项。
 * L: Lua状态机，用于访问Lua栈和Lua环境。
 * 返回值: 成功时返回匹配项的索引，失败时返回0。
 */
static int str_find (lua_State *L) {
  return str_find_aux(L, 1);
}

/* 
 * 查找字符串中指定模式的所有匹配项。
 * L: Lua状态机，用于访问Lua栈和Lua环境。
 * 返回值: 成功时返回匹配项的索引，失败时返回0。
 */
static int str_match (lua_State *L) {
  return str_find_aux(L, 0);
}

/*
 * 'gmatch'操作的状态结构体。
 * src: 当前搜索位置。
 * p: 搜索模式。
 * lastmatch: 上一次匹配的结束位置。
 * ms: 匹配状态，用于执行正则表达式匹配。
 */
typedef struct GMatchState {
  const char *src;  
  const char *p;  
  const char *lastmatch;  
  MatchState ms;  
} GMatchState;

/*
 * 辅助函数，用于实现'gmatch'函数。
 * L: Lua状态机。
 * 返回值: 找到匹配时返回1，否则返回0。
 */
static int gmatch_aux (lua_State *L) {
  GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
  const char *src;
  gm->ms.L = L;
  /* 遍历字符串，寻找匹配模式的每个实例 */
  for (src = gm->src; src <= gm->ms.src_end; src++) {
    const char *e;
    reprepstate(&gm->ms);
    /* 如果找到匹配且与上一次匹配不重叠，则更新匹配信息并返回 */
    if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
      gm->src = gm->lastmatch = e;
      return push_captures(&gm->ms, src, e);
    }
  }
  return 0;  /* 未找到匹配项 */
}


/*
 * gmatch函数: 在给定的字符串中根据正则表达式进行全局匹配。
 * 
 * 参数:
 * L - Lua状态机指针。
 * 
 * 返回值:
 * 返回1，表示函数向Lua栈中压入了一个元素。
 */
static int gmatch (lua_State *L) {
  size_t ls, lp; // 分别用于存储字符串s和p的长度。
  const char *s = luaL_checklstring(L, 1, &ls); // 检查并获取Lua栈中第一个字符串参数。
  const char *p = luaL_checklstring(L, 2, &lp); // 检查并获取Lua栈中第二个字符串参数。
  size_t init = posrelatI(luaL_optinteger(L, 3, 1), ls) - 1; // 计算匹配的起始位置。
  GMatchState *gm;
  lua_settop(L, 2);  /* 保留字符串在闭包中以避免被收集 */
  gm = (GMatchState *)lua_newuserdatauv(L, sizeof(GMatchState), 0); // 在Lua栈中创建一个用于GMatchState的新用户数据。
  if (init > ls)  /* 如果起始位置超过字符串长度，则调整起始位置 */
    init = ls + 1;  /* 避免除法溢出 */
  prepstate(&gm->ms, L, s, ls, p, lp); // 初始化匹配状态。
  gm->src = s + init; gm->p = p; gm->lastmatch = NULL; // 设置匹配的起始点和其他状态。
  lua_pushcclosure(L, gmatch_aux, 3); // 创建并压入一个闭包。
  return 1;
}

/*
 * add_s函数: 将匹配到的字符串添加到替换结果中。
 * 
 * 参数:
 * ms - 匹配状态指针。
 * b - Lua字符串缓冲区，用于构建最终的替换结果。
 * s - 源字符串的起始指针。
 * e - 源字符串中当前匹配的结束指针。
 */
static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
                                                   const char *e) {
  size_t l;
  lua_State *L = ms->L;
  const char *news = lua_tolstring(L, 3, &l); // 获取替换字符串。
  const char *p;
  // 遍历替换字符串，处理特殊字符。
  while ((p = (char *)memchr(news, L_ESC, l)) != NULL) {
    luaL_addlstring(b, news, p - news); // 添加未处理的部分。
    p++;  /* 跳过转义字符 */
    if (*p == L_ESC)  /* 处理'%%' */
      luaL_addchar(b, *p);
    else if (*p == '0')  /* 处理'%0'，添加匹配的源字符串部分。 */
        luaL_addlstring(b, s, e - s);
    else if (isdigit(uchar(*p))) {  /* 处理'%n'，添加捕获的内容。 */
      const char *cap;
      ptrdiff_t resl = get_onecapture(ms, *p - '1', s, e, &cap);
      if (resl == CAP_POSITION)
        luaL_addvalue(b);  /* 添加位置到结果中 */
      else
        luaL_addlstring(b, cap, resl);
    }
    else
      luaL_error(L, "invalid use of在替换字符串中使用 '%c' 不正确in replacement string", L_ESC);
    l -= p + 1 - news; // 更新剩余字符串长度。
    news = p + 1; // 更新新闻的起始位置。
  }
  luaL_addlstring(b, news, l); // 添加剩余未处理字符串。
}


/*
** 向字符串缓冲区'b'添加替换值。
** 如果原始字符串被改变，则返回true。（函数调用和导致nil或false的表索引不会改变主题。）
*/
static int add_value (MatchState *ms, luaL_Buffer *b, const char *s,
                                      const char *e, int tr) {
  lua_State *L = ms->L;
  // 根据替换类型（tr），执行不同的操作
  switch (tr) {
    case LUA_TFUNCTION: {  /* 调用函数进行替换 */
      int n;
      lua_pushvalue(L, 3);  /* 将函数压入堆栈 */
      n = push_captures(ms, s, e);  /* 将所有捕获作为参数压入堆栈 */
      lua_call(L, n, 1);  /* 调用函数 */
      break;
    }
    case LUA_TTABLE: {  /* 使用表进行索引替换 */
      push_onecapture(ms, 0, s, e);  /* 将第一个捕获作为索引压入堆栈 */
      lua_gettable(L, 3);  /* 从表中获取值 */
      break;
    }
    default: {  /* 当替换类型为LUA_TNUMBER或LUA_TSTRING时，直接添加到缓冲区 */
      add_s(ms, b, s, e);  /* 将值添加到缓冲区 */
      return 1;  /* 表示有更改 */
    }
  }
  // 处理函数调用或表索引结果为nil或false的情况
  if (!lua_toboolean(L, -1)) {  /* 如果结果为nil或false？ */
    lua_pop(L, 1);  /* 移除结果值 */
    luaL_addlstring(b, s, e - s);  /* 保持原始文本 */
    return 0;  /* 没有更改 */
  }
  else if (l_unlikely(!lua_isstring(L, -1)))
    return luaL_error(L, "invalid replacement value(a无效的替换值 %s)",
                         luaL_typename(L, -1));  /* 处理无效的替换值 */
  else {
    luaL_addvalue(b);  /* 将结果添加到累加器 */
    return 1;  /* 表示有更改 */
  }
}

/*
 * 在Lua中执行字符串的全局替换。
 * 
 * 参数:
 *   L - Lua状态机指针。
 * 
 * 返回值:
 *   返回两个值：替换后的字符串和替换次数。
 */

static int str_gsub (lua_State *L) {
  size_t srcl, lp; // 输入字符串长度和模式字符串长度
  const char *src = luaL_checklstring(L, 1, &srcl);  /* 需要替换的原始字符串 */
  const char *p = luaL_checklstring(L, 2, &lp);  /* 用于匹配的模式字符串 */
  const char *lastmatch = NULL;  /* 上一次匹配的结束位置 */
  int tr = lua_type(L, 3);  /* 替换目标的类型 */
  lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);  /* 最大替换次数 */
  int anchor = (*p == '^');  /* 检查模式字符串是否以'^'开头，表示匹配必须从字符串开始处开始 */
  lua_Integer n = 0;  /* 替换计数 */
  int changed = 0;  /* 标记是否发生了替换 */
  MatchState ms;  /* 匹配状态 */
  luaL_Buffer b;  /* 用于构建替换后字符串的缓冲区 */
  
  // 检查替换目标的类型是否正确
  luaL_argexpected(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
                   tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
                      "string/function/table");
  
  luaL_buffinit(L, &b);  /* 初始化构建缓冲区 */

  if (anchor) {  /* 如果模式以'^'开头，则跳过该字符 */
    p++; lp--;
  }

  // 准备匹配状态
  prepstate(&ms, L, src, srcl, p, lp);
  
  while (n < max_s) {  /* 执行最大替换次数次循环 */
    const char *e;
    reprepstate(&ms);  /* 为新的匹配重新准备状态 */
    if ((e = match(&ms, src, p)) != NULL && e != lastmatch) {  /* 如果找到匹配，并且与上一次匹配的结束位置不同 */
      n++;
      changed = add_value(&ms, &b, src, e, tr) | changed;  /* 添加替换的值到结果中 */
      src = lastmatch = e;  /* 更新源字符串的起始位置和上一次匹配的结束位置 */
    }
    else if (src < ms.src_end)  /* 如果没有找到匹配，或者与上一次匹配的结束位置相同，则跳过一个字符 */
      luaL_addchar(&b, *src++);
    else break;  /* 如果源字符串处理完毕，则退出循环 */
    if (anchor) break;  /* 如果设置了锚点，即模式以'^'开头，则在第一次匹配后退出循环 */
  }

  if (!changed) {  /* 如果没有发生替换，则返回原始字符串 */
    lua_pushvalue(L, 1);
  }
  else {  /* 如果发生了替换，则构建并返回新的字符串 */
    luaL_addlstring(&b, src, ms.src_end-src);
    luaL_pushresult(&b);
  }
  
  lua_pushinteger(L, n);  /* 将替换次数推入Lua栈中 */
  return 2;  /* 返回替换后的字符串和替换次数 */
}

/* }====================================================== */



/*
** {======================================================
** STRING FORMAT
** =======================================================
*/

#if !defined(lua_number2strx)	/* { */

/*
** 这一部分代码定义了将数值转换为十六进制字符串的函数。
*/

#define SIZELENMOD	(sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))


/*
** 确定第一个数字进入的位数。该值可以在1到4之间任意选择；以下定义试图通过使
** 第一个数字之后的内容成为4的倍数来对数字进行字节对齐。
*/
#define L_NBFD		((l_floatatt(MANT_DIG) - 1)%4 + 1)


/*
** 将数字的整数部分添加到缓冲区并返回新的数字。
*/
static lua_Number adddigit (char *buff, int n, lua_Number x) {
  lua_Number dd = l_mathop(floor)(x);  /* 从 'x' 获取整数部分 */
  int d = (int)dd;
  buff[n] = (d < 10 ? d + '0' : d - 10 + 'a');  /* 将其添加到缓冲区 */
  return x - dd;  /* 返回剩余部分 */
}


/*
** 将数值转换为辅助字符串格式。
**
** @param buff 存储转换结果的缓冲区。
** @param sz 缓冲区的大小。
** @param x 要转换的数值。
** @return 转换后的字符串长度。
*/
static int num2straux (char *buff, int sz, lua_Number x) {
  /* 如果是'inf'或'NaN'，则按照'%g'格式格式化 */
  if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
    return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
  else if (x == 0) {  /* 可能为-0... */
    /* 生成"0"或"-0"，后面跟随指数 */
    return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x);
  }
  else {
    int e;
    lua_Number m = l_mathop(frexp)(x, &e);  /* 获取 'x' 的小数部分和指数 */
    int n = 0;  /* 字符计数 */
    if (m < 0) {  /* 数字是否为负？ */
      buff[n++] = '-';  /* 添加符号 */
      m = -m;  /* 使其为正 */
    }
    buff[n++] = '0'; buff[n++] = 'x';  /* 添加 "0x" */
    m = adddigit(buff, n++, m * (1 << L_NBFD));  /* 添加第一个数字 */
    e -= L_NBFD;  /* 此数字在小数点之前 */
    if (m > 0) {  /* 还有更多数字？ */
      buff[n++] = lua_getlocaledecpoint();  /* 添加小数点 */
      do {  /* 添加所需数字 */
        m = adddigit(buff, n++, m * 16);
      } while (m > 0);
    }
    n += l_sprintf(buff + n, sz - n, "p%+d", e);  /* 添加指数 */
    lua_assert(n < sz);
    return n;
  }
}


/*
** 将数值转换为指定格式的字符串。
**
** @param L Lua状态机。
** @param buff 存储转换结果的缓冲区。
** @param sz 缓冲区的大小。
** @param fmt 格式字符串。
** @param x 要转换的数值。
** @return 转换后的字符串长度。
*/
static int lua_number2strx (lua_State *L, char *buff, int sz,
                            const char *fmt, lua_Number x) {
  int n = num2straux(buff, sz, x);
  if (fmt[SIZELENMOD] == 'A') {
    int i;
    for (i = 0; i < n; i++)
      buff[i] = toupper(uchar(buff[i]));  /* 转换为大写 */
  }
  else if (l_unlikely(fmt[SIZELENMOD] != 'a'))
    return luaL_error(L, "modifiers for format格式 '%%a' /'%%A' 的修饰符尚未实现not implemented");
  return n;
}

#endif				/* } */				/* } */


/*
** 定义与浮点数格式化相关的最大长度限制。
**
** '%f'格式化所需的最长字符数是由'%.99f'格式化最大浮点数产生的，
** 其长度等于99（最大精度）+ 3（'-'、'.'和'\0'）+ 表示最大浮点数的十进制位数（最大指数+1）。
** （99+3+1，额外增加一些空间，总共110）
*/
#define MAX_ITEMF	(110 + l_floatatt(MAX_10_EXP))


/*
** 除了'%f'格式外，其他所有格式不需要如此大的限制。
** 其他浮点数格式使用指数表示，因此它们适应于对于有意义的数字限制在99位；
** 's'格式用于大型字符串，'q'格式直接将项目添加到缓冲区；
** 所有整数格式也适应于99位的限制。最坏的情况是浮点数：
** 它们可能需要99位有意义的数字，加上'0x'、'-'、'.'、'e+XXXX'和'\0'。
** 额外增加一些空间，总共120。
*/
#define MAX_ITEM	120


/* 格式规范中有效的标志 */
#if !defined(L_FMTFLAGSF)

/* 对于a, A, e, E, f, F, g, 和 G转换有效的标志 */
#define L_FMTFLAGSF	"-+#0 "

/* 对于o, x, 和 X转换有效的标志 */
#define L_FMTFLAGSX	"-#0"

/* 对于d 和 i转换有效的标志 */
#define L_FMTFLAGSI	"-+0 "

/* 对于u转换有效的标志 */
#define L_FMTFLAGSU	"-0"

/* 对于c, p, 和 s转换有效的标志 */
#define L_FMTFLAGSC	"-"

#endif


/*
** 定义每个格式规范（如"%-099.99d"）的最大大小：
** 初始 '%'，标志（最多 5 个），宽度（2 个），小数点，精度（2 个），
** 长度修饰符（8 个），转换说明符，和最终的 '\0'，再加上一些额外的空间。
*/
#define MAX_FORMAT	32


/*
** 将字符串 s 中的每个字符添加到 luaL_Buffer b 中，并对特殊字符进行转义。
** 特殊字符包括双引号、反斜线和换行符。对于控制字符，使用转义序列表示。
** 
** @param b luaL_Buffer*，目标缓冲区，用于收集格式化后的字符串。
** @param s const char*，源字符串，需要被添加到缓冲区的字符串。
** @param len size_t，源字符串 s 的长度。
*/
static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
  luaL_addchar(b, '"'); /* 在缓冲区开始处添加一个双引号 */
  while (len--) { /* 遍历源字符串 */
    if (*s == '"' || *s == '\\' || *s == '\n') { /* 对双引号、反斜线和换行符进行转义 */
      luaL_addchar(b, '\\');
      luaL_addchar(b, *s);
    }
    else if (iscntrl(uchar(*s))) { /* 如果当前字符是控制字符，则使用转义序列表示 */
      char buff[10];
      if (!isdigit(uchar(*(s+1)))) /* 对于非数字后的控制字符，使用 "\ddd" 格式 */
        l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
      else /* 对于数字后的控制字符，使用 "\ddd" 格式，确保三位数字 */
        l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
      luaL_addstring(b, buff); /* 将转义序列添加到缓冲区 */
    }
    else /* 对于普通字符，直接添加到缓冲区 */
      luaL_addchar(b, *s);
    s++; /* 指向下一个字符 */
  }
  luaL_addchar(b, '"'); /* 在缓冲区结束处添加一个双引号 */
}


/*
** 将浮点数序列化，使其可以被Lua扫描读取回来。对于“普通”数字使用十六进制格式（以保留精度）；
** inf、-inf和NaN分别特殊处理。 （NaN不能作为数值表达，因此我们将其表示为'(0/0)'。）
*/
static int quotefloat (lua_State *L, char *buff, lua_Number n) {
  const char *s;  /* 用于固定表示形式的字符串 */
  if (n == (lua_Number)HUGE_VAL)  /* 判断是否为正无穷大 */
    s = "1e9999";
  else if (n == -(lua_Number)HUGE_VAL)  /* 判断是否为负无穷大 */
    s = "-1e9999";
  else if (n != n)  /* 判断是否为NaN */
    s = "(0/0)";
  else {  /* 以十六进制格式化数字 */
    int  nb = lua_number2strx(L, buff, MAX_ITEM,
                                 "%" LUA_NUMBER_FRMLEN "a", n);
    /* 确保‘buff’字符串使用点作为基数字符 */
    if (memchr(buff, '.', nb) == NULL) {  /* 如果没有点号？ */
      char point = lua_getlocaledecpoint();  /* 尝试使用本地点号 */
      char *ppoint = (char *)memchr(buff, point, nb);
      if (ppoint) *ppoint = '.';  /* 将其改为点号 */
    }
    return nb;
  }
  /* 对于固定表示形式 */
  return l_sprintf(buff, MAX_ITEM, "%s", s);
}


/*
 * 将不同类型的Lua值转换为其字面量形式，并添加到给定的luaL_Buffer中。
 * 
 * @param L lua_State的指针，表示当前的Lua环境。
 * @param b luaL_Buffer的指针，表示目标缓冲区，将把转换后的字面量添加到此缓冲区。
 * @param arg 指定要转换的Lua值在栈上的位置。
 */
static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
  switch (lua_type(L, arg)) { // 根据栈上指定位置的元素类型进行处理
    case LUA_TSTRING: { // 当元素为字符串时
      size_t len;
      const char *s = lua_tolstring(L, arg, &len); // 将Lua栈上的元素转换为字符串
      addquoted(b, s, len); // 添加带引号的字符串到缓冲区
      break;
    }
    case LUA_TNUMBER: { // 当元素为数字时
      char *buff = luaL_prepbuffsize(b, MAX_ITEM); // 准备缓冲区以存储转换后的字面量
      int nb;
      if (!lua_isinteger(L, arg))  /* 如果是浮点数？ */
        nb = quotefloat(L, buff, lua_tonumber(L, arg)); // 处理浮点数
      else {  /* 如果是整数 */
        lua_Integer n = lua_tointeger(L, arg);
        const char *format = (n == LUA_MININTEGER)  /* 如果是边界情况整数？ */
                           ? "0x%" LUA_INTEGER_FRMLEN "x"  /* 使用十六进制格式 */
                           : LUA_INTEGER_FMT;  /* 否则使用默认格式 */
        nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); // 使用指定格式转换整数
      }
      luaL_addsize(b, nb); // 将转换后的字面量长度添加到缓冲区
      break;
    }
    case LUA_TNIL: case LUA_TBOOLEAN: { // 当元素为nil或者布尔值时
      luaL_tolstring(L, arg, NULL); // 将nil或布尔值转换为字符串
      luaL_addvalue(b); // 将转换后的字符串添加到缓冲区
      break;
    }
    default: { // 对于不支持的类型，抛出错误
      luaL_argerror(L, arg, "该值没有字面形式value has no literal form");
    }
  }
}


/*
 * 获取包含至少两个数字字符的字符串指针。
 * 参数：
 *   s: 指向可能包含数字的字符串的指针。
 * 返回值：
 *   返回指向至少包含两个数字字符的子字符串的指针，如果没有找到这样的子字符串，则返回原字符串指针。
 */
static const char *get2digits (const char *s) {
  if (isdigit(uchar(*s))) {  // 检查第一个字符是否为数字
    s++;
    if (isdigit(uchar(*s))) s++;  /* 如果是，继续检查第二个字符是否为数字 */
  }
  return s;
}

/*
 * 检查格式化字符串是否有效。
 * 参数：
 *   L: Lua状态机指针。
 *   form: 指向待检查格式化字符串的指针。
 *   flags: 接受的标志字符集合。
 *   precision: 是否接受精度指示。
 */
static void checkformat (lua_State *L, const char *form, const char *flags,
                                       int precision) {
  const char *spec = form + 1;  /* 跳过 '%' 字符 */
  spec += strspn(spec, flags);  /* 跳过所有标志字符 */
  if (*spec != '0') {  /* 宽度指示不能以 '0' 开头 */
    spec = get2digits(spec);  /* 跳过宽度指示 */
    if (*spec == '.' && precision) {  /* 检查是否有精度指示 */
      spec++;
      spec = get2digits(spec);  /* 跳过精度值 */
    }
  }
  if (!isalpha(uchar(*spec)))  /* 如果当前字符不是字母，说明格式化字符串不合法 */
    luaL_error(L, "invalid conversion specification无效的转换说明符: '%s'", form);
}


/*
** 获取转换规范并将它复制到 'form' 中。
** 返回该规范的最后一个字符的地址。
*/
static const char *getformat (lua_State *L, const char *strfrmt,
                                            char *form) {
  /* 计算包括标志、宽度和精度（'0' 作为标志之一）的跨度 */
  size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789.");
  len++;  /* 添加随后的字符（应该是规范说明符） */
  /* 需要空间来放置 '%'、'\0'，以及长度修饰符 */
  if (len >= MAX_FORMAT - 10)
    luaL_error(L, "invalid format (too long)无效的格式（太长）"); /* 格式无效（太长） */
  *(form++) = '%'; /* 添加 '%' 字符 */
  memcpy(form, strfrmt, len * sizeof(char)); /* 复制格式字符串 */
  *(form + len) = '\0'; /* 添加字符串结束符 */
  return strfrmt + len - 1; /* 返回规范的最后一个字符的地址 */
}

/*
** add length modifier into formats
** 该函数用于将长度修饰符添加到格式化字符串中。
**
** 参数:
**   form - 指向需要修改的格式化字符串的指针。
**   lenmod - 指向要添加的长度修饰符字符串的指针。
** 
** 返回值:
**   该函数没有返回值。
*/
static void addlenmod (char *form, const char *lenmod) {
  // 获取原始格式化字符串的长度
  size_t l = strlen(form);
  // 获取长度修饰符字符串的长度
  size_t lm = strlen(lenmod);
  // 获取原始格式化字符串最后一个字符，它将被长度修饰符替换
  char spec = form[l - 1];
  // 将长度修饰符插入到原始格式化字符串的最后
  strcpy(form + l - 1, lenmod);
  // 恢复原始格式化字符串的最后一个字符
  form[l + lm - 1] = spec;
  // 添加字符串结束符，确保字符串正确结束
  form[l + lm] = '\0';
}


/*
 * 格式化字符串并将其推送到 Lua 栈上。
 *
 * 参数:
 *   L - Lua 状态机的指针。
 *
 * 返回值:
 *   返回 1，表示在 Lua 栈上推送了一个结果。
 */
static int str_format (lua_State *L) {
  // 获取 Lua 栈顶
  int top = lua_gettop(L);
  int arg = 1; // 参数索引
  size_t sfl; // 格式字符串的长度
  // 检查并获取格式化字符串
  const char *strfrmt = luaL_checklstring(L, arg, &sfl);
  const char *strfrmt_end = strfrmt+sfl; // 格式化字符串的结束位置
  const char *flags;
  luaL_Buffer b; // 用于构建结果字符串的缓冲区
  luaL_buffinit(L, &b);
  // 遍历格式化字符串
  while (strfrmt < strfrmt_end) {
    if (*strfrmt != L_ESC)
      luaL_addchar(&b, *strfrmt++); // 处理非转义字符
    else if (*++strfrmt == L_ESC)
      luaL_addchar(&b, *strfrmt++); // 处理连续的百分号 %%
    else { // 处理格式化项
      char form[MAX_FORMAT]; // 存储格式字符串 ('%...')
      int maxitem = MAX_ITEM; // 结果字符串的最大长度
      char *buff = luaL_prepbuffsize(&b, maxitem); // 准备存放结果的缓冲区
      int nb = 0; // 结果字符串的字节数
      if (++arg > top)
        return luaL_argerror(L, arg, "参数不足no value"); // 参数不足，返回错误
      strfrmt = getformat(L, strfrmt, form); // 获取格式化项
      switch (*strfrmt++) {
        // 处理各种格式化选项
        case 'c': {
          checkformat(L, form, L_FMTFLAGSC, 0);
          nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg));
          break;
        }
        // 整数类型格式化（十进制、八进制、十六进制）
        case 'd': case 'i':
          flags = L_FMTFLAGSI;
          goto intcase;
        case 'u':
          flags = L_FMTFLAGSU;
          goto intcase;
        case 'o': case 'x': case 'X':
          flags = L_FMTFLAGSX;
        intcase: {
          lua_Integer n = luaL_checkinteger(L, arg);
          checkformat(L, form, flags, 1);
          addlenmod(form, LUA_INTEGER_FRMLEN);
          nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n);
          break;
        }
        // 浮点数格式化
        case 'a': case 'A':
          checkformat(L, form, L_FMTFLAGSF, 1);
          addlenmod(form, LUA_NUMBER_FRMLEN);
          nb = lua_number2strx(L, buff, maxitem, form,
                                  luaL_checknumber(L, arg));
          break;
        case 'f':
          maxitem = MAX_ITEMF; // '%f' 需要额外的空间
          buff = luaL_prepbuffsize(&b, maxitem);
          /* FALLTHROUGH */
        case 'e': case 'E': case 'g': case 'G': {
          lua_Number n = luaL_checknumber(L, arg);
          checkformat(L, form, L_FMTFLAGSF, 1);
          addlenmod(form, LUA_NUMBER_FRMLEN);
          nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
          break;
        }
        // 指针格式化
        case 'p': {
          const void *p = lua_topointer(L, arg);
          checkformat(L, form, L_FMTFLAGSC, 0);
          if (p == NULL) { // 避免传入 NULL 给 printf
            p = "(null)"; // 用字符串代替
            form[strlen(form) - 1] = 's'; // 修改格式为字符串
          }
          nb = l_sprintf(buff, maxitem, form, p);
          break;
        }
        // 字符串格式化
        case 'q': {
          if (form[2] != '\0') // 检查是否有修饰符
            return luaL_error(L, "specifier格式说明符 '%%q' 不能带有修饰符cannot have modifiers");
          addliteral(L, &b, arg);
          break;
        }
        case 's': {
          size_t l;
          const char *s = luaL_tolstring(L, arg, &l);
          if (form[2] == '\0') // 检查是否有修饰符
            luaL_addvalue(&b); // 直接添加整个字符串
          else {
            luaL_argcheck(L, l == strlen(s), arg, "字符串包含零string contains zeros");
            checkformat(L, form, L_FMTFLAGSC, 1);
            if (strchr(form, '.') == NULL && l >= 100) { // 无精度且字符串过长
              luaL_addvalue(&b); // 直接添加整个字符串
            }
            else { // 格式化字符串
              nb = l_sprintf(buff, maxitem, form, s);
              lua_pop(L, 1); // 移除 luaL_tolstring 添加的字符串
            }
          }
          break;
        }
        default: {
          return luaL_error(L, " invalid conversion将 '%s' to转换为 'format'无效", form);
        }
      }
      lua_assert(nb < maxitem);
      luaL_addsize(&b, nb);
    }
  }
  luaL_pushresult(&b); // 将结果字符串推送到 Lua 栈上
  return 1;
}

/* }====================================================== */


/*
** {======================================================
** PACK/UNPACK
** =======================================================
*/

/* 定义用于填充的值 */
#if !defined(LUAL_PACKPADBYTE)
#define LUAL_PACKPADBYTE		0x00  /* 默认填充字节为0x00 */
#endif

/* 二进制表示整数的最大大小 */
#define MAXINTSIZE	16  /* 整数的最大二进制长度为16位 */

/* 一个字符包含的比特数 */
#define NB	CHAR_BIT  /* 字符的比特数，通常为8 */

/* 一个字符的1的掩码 */
#define MC	((1 << NB) - 1)  /* 一个字符所有位均为1的掩码 */

/* lua_Integer类型的大小 */
#define SZINT	((int)sizeof(lua_Integer))  /* lua_Integer类型的字节大小 */

/*
** 用于判断机器字节序的伪联合体
*/
static const union {
  int dummy;  /* 闲置字段 */
  char little;  /* 如果机器为小端则为true */
} nativeendian = {1};  /* 初始化联合体，通过小端字段判断机器字节序 */

/*
** pack/unpack操作所需信息
*/
typedef struct Header {
  lua_State *L;  /* Lua状态机 */
  int islittle;  /* 标记字节序是否为小端 */
  int maxalign;  /* 最大对齐因子 */
} Header;  /* 包含操作所需通用信息的结构体 */

/*
** pack/unpack选项枚举
*/
typedef enum KOption {
  Kint,		/* 有符号整数 */
  Kuint,	/* 无符号整数 */
  Kfloat,	/* 单精度浮点数 */
  Knumber,	/* Lua的"原生"浮点数 */
  Kdouble,	/* 双精度浮点数 */
  Kchar,	/* 定长字符串 */
  Kstring,	/* 带前缀长度的字符串 */
  Kzstr,	/* 以零结尾的字符串 */
  Kpadding,	/* 填充 */
  Kpaddalign,	/* 对齐填充 */
  Knop		/* 无操作（配置或空格） */
} KOption;  /* 包含所有可用操作类型的枚举 */

/*
** 判断给定字符是否为数字
** 参数:
**   c - 待判断的字符
** 返回值:
**   如果字符是数字，则返回真；否则返回假。
*/
static int digit (int c) { return '0' <= c && c <= '9'; }

/*
** 从格式化字符串中读取一个整数数字，如果没有数字则返回默认值
** 参数:
**   fmt - 指向格式化字符串的指针的地址
**   df - 默认返回值
** 返回值:
**   读取到的整数或者默认值
*/
static int getnum (const char **fmt, int df) {
  if (!digit(**fmt))  /* 没有数字？ */
    return df;  /* 返回默认值 */
  else {
    int a = 0;
    do {
      a = a*10 + (*((*fmt)++) - '0'); /* 逐个字符读取并转换为整数 */
    } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);
    return a;
  }
}

/*
** 读取一个整数数字，并在超出整数大小限制时引发错误
** 参数:
**   h - 指向Header结构体的指针
**   fmt - 指向格式化字符串的指针的地址
**   df - 默认返回值
** 返回值:
**   读取到的整数，如果超出大小限制则引发错误
*/
static int getnumlimit (Header *h, const char **fmt, int df) {
  int sz = getnum(fmt, df); /* 读取整数 */
  if (l_unlikely(sz > MAXINTSIZE || sz <= 0))
    return luaL_error(h->L, "integral size整数大小 (%d) 超出限制范围out of limits [1,%d]",
                            sz, MAXINTSIZE); /* 检查并处理超出大小限制的情况 */
  return sz;
}


/*
** 初始化Header结构体
** 参数:
**   L - Lua状态机
**   h - 指向Header结构体的指针
*/
static void initheader (lua_State *L, Header *h) {
  h->L = L; /* 存储Lua状态机指针 */
  h->islittle = nativeendian.little; /* 存储系统的小端标志 */
  h->maxalign = 1; /* 初始化最大对齐值 */
}


/*
** 读取并分类下一个选项。'size'将被填充为选项的大小。
*/
static KOption getoption (Header *h, const char **fmt, int *size) {
  /* 用于获取本机对齐要求的虚拟结构 */
  struct cD { char c; union { LUAI_MAXALIGN; } u; };
  
  int opt = *((*fmt)++); // 读取当前格式字符，并将指针向前移动一位
  *size = 0;  /* 默认大小 */
  switch (opt) { // 根据读取的格式字符进行不同的处理
    // 对应不同的数据类型和大小
    case 'b': *size = sizeof(char); return Kint;
    case 'B': *size = sizeof(char); return Kuint;
    case 'h': *size = sizeof(short); return Kint;
    case 'H': *size = sizeof(short); return Kuint;
    case 'l': *size = sizeof(long); return Kint;
    case 'L': *size = sizeof(long); return Kuint;
    case 'j': *size = sizeof(lua_Integer); return Kint;
    case 'J': *size = sizeof(lua_Integer); return Kuint;
    case 'T': *size = sizeof(size_t); return Kuint;
    case 'f': *size = sizeof(float); return Kfloat;
    case 'n': *size = sizeof(lua_Number); return Knumber;
    case 'd': *size = sizeof(double); return Kdouble;
    // 根据平台的int大小动态获取大小
    case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
    case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
    // 字符串处理
    case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
    // 字符大小动态获取，缺失大小则报错
    case 'c':
      *size = getnum(fmt, -1);
      if (l_unlikely(*size == -1))
        luaL_error(h->L, "missing size for format option格式选项 'c' 缺少大小");
      return Kchar;
    // 特殊选项处理
    case 'z': return Kzstr;
    case 'x': *size = 1; return Kpadding;
    case 'X': return Kpaddalign;
    // 格式标志位处理
    case ' ': break;
    case '<': h->islittle = 1; break;
    case '>': h->islittle = 0; break;
    case '=': h->islittle = nativeendian.little; break;
    // 最大对齐值获取
    case '!': {
      const int maxalign = offsetof(struct cD, u);
      h->maxalign = getnumlimit(h, fmt, maxalign);
      break;
    }
    // 无效格式选项处理
    default: luaL_error(h->L, "invalid format option无效的格式选项 '%c'", opt);
  }
  return Knop; // 未匹配到任何情况时返回Knop
}

/*
** 此函数用于读取、分类并填充下一个选项的详细信息。
** 它会填充选项的大小到'psize'，其对齐要求到'ntoalign'。
** 局部变量'size'获取需要对齐的大小。Kpadal选项总是获取其完整的对齐，
** 其他选项则受最大对齐值('maxalign')的限制。Kchar选项不需要对齐，尽管其大小可能需要。
**
** @param h 指向Header结构的指针，包含有关正在处理的选项集的元数据。
** @param totalsize 到目前为止已处理选项的总大小。
** @param fmt 指向格式字符串的指针，该字符串描述了接下来要处理的选项。
** @param psize 指向整数的指针，函数会在此处存储选项的大小。
** @param ntoalign 指向整数的指针，函数会在此处存储选项的对齐要求。
** @return 返回一个KOption枚举值，表示识别的选项类型。
*/
static KOption getdetails (Header *h, size_t totalsize,
                           const char **fmt, int *psize, int *ntoalign) {
  KOption opt = getoption(h, fmt, psize);  // 获取当前选项的类型和大小
  int align = *psize;  /* 通常，对齐要求跟在大小后面 */
  if (opt == Kpaddalign) {  // 特殊处理对齐选项'X'
    // 如果格式字符串结束或下一个选项是Kchar或对齐要求为0，则报错
    if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
      luaL_argerror(h->L, 1, "invalid next option for option 'X' 选项的下一个选项无效");
  }
  // 如果对齐要求小于等于1或选项是Kchar，则不需要对齐
  if (align <= 1 || opt == Kchar)  
    *ntoalign = 0;
  else {
    // 强制实施最大对齐要求
    if (align > h->maxalign)  
      align = h->maxalign;
    // 如果对齐要求不是2的幂，则报错
    if (l_unlikely((align & (align - 1)) != 0))  
      luaL_argerror(h->L, 1, "格式要求的对齐不是2的幂format asks for alignment not power of 2");
    // 计算需要的对齐空间
    *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
  }
  return opt;  // 返回识别的选项类型
}

/*
** 此函数将无符号整数'n'以指定的'大小'字节和'islittle'字节序打包。
** 最后的'if'语句处理'大小'大于Lua整数大小的情况，
** 在这种情况下，如果需要的话，会修正额外的符号扩展字节（默认情况下它们是零）。
**
** 参数:
** b - luaL_Buffer结构指针，用于存储打包后的数据。
** n - 要打包的无符号整数。
** islittle - 指示字节序是否为小端的布尔值。
** size - 打包的整数大小（以字节为单位）。
** neg - 指示整数是否为负数的布尔值。
*/
static void packint (luaL_Buffer *b, lua_Unsigned n,
                     int islittle, int size, int neg) {
  char *buff = luaL_prepbuffsize(b, size);  // 准备缓冲区，大小为'size'。
  int i;
  buff[islittle ? 0 : size - 1] = (char)(n & MC);  // 写入第一个字节。
  // 循环将整数的每个字节写入缓冲区。
  for (i = 1; i < size; i++) {
    n >>= NB;  // 右移操作，为下一个字节做准备。
    buff[islittle ? i : size - 1 - i] = (char)(n & MC);
  }
  // 如果是负数并且'size'大于Lua整数的大小，则需要进行符号扩展。
  if (neg && size > SZINT) {
    for (i = SZINT; i < size; i++)  // 修正额外的字节。
      buff[islittle ? i : size - 1 - i] = (char)MC;
  }
  luaL_addsize(b, size);  // 将结果添加到缓冲区。
}

/*
** 从'src'复制'size'字节到'dest'，如果给定的'islittle'与本地字节序不同，
** 则会纠正字节序。
**
** 参数:
** dest - 目标缓冲区的指针。
** src - 源缓冲区的指针。
** size - 要复制的字节数。
** islittle - 指示字节序是否为小端的布尔值。
*/
static void copywithendian (char *dest, const char *src,
                            int size, int islittle) {
  // 如果字节序相同，则直接复制。
  if (islittle == nativeendian.little)
    memcpy(dest, src, size);
  else {
    // 如果字节序不同，则反向复制以纠正字节序。
    dest += size - 1;
    while (size-- != 0)
      *(dest--) = *(src++);
  }
}

/*
 * 将各种类型的数据按照指定的格式打包到一个字符串中。
 * 
 * @param L Lua状态机，用于访问Lua栈中的参数和返回结果。
 * @return 返回1，表示函数向Lua栈中压入了一个结果。
 */
static int str_pack (lua_State *L) {
  luaL_Buffer b; // 用于构建最终结果的缓冲区
  Header h; // 包含打包信息的头部结构体
  const char *fmt = luaL_checkstring(L, 1);  /* 格式字符串，指定打包格式 */
  int arg = 1;  /* 当前处理的参数位置 */
  size_t totalsize = 0;  /* 结果的总大小 */
  initheader(L, &h); // 初始化头部结构体
  lua_pushnil(L);  /* 在栈上放置一个nil，作为参数和结果字符串的分界 */
  luaL_buffinit(L, &b); // 初始化Lua的缓冲区

  // 遍历格式字符串，处理每个格式指示符
  while (*fmt != '\0') {
    int size, ntoalign;
    KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); // 获取当前格式指示符的详细信息
    totalsize += ntoalign + size; // 更新总大小，包括对齐填充
    while (ntoalign-- > 0)
     luaL_addchar(&b, LUAL_PACKPADBYTE);  /* 对齐填充 */

    arg++; // 处理下一个参数
    switch (opt) {
      case Kint: {  /* 打包有符号整数 */
        lua_Integer n = luaL_checkinteger(L, arg);
        if (size < SZINT) {  /* 检查整数溢出 */
          lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
          luaL_argcheck(L, -lim <= n && n < lim, arg, "整数溢出integer overflow");
        }
        packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0));
        break;
      }
      case Kuint: {  /* 打包无符号整数 */
        lua_Integer n = luaL_checkinteger(L, arg);
        if (size < SZINT)  /* 检查无符号整数溢出 */
          luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
                           arg, "无符号整数溢出unsigned overflow");
        packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
        break;
      }
      // 打包浮点数和双精度浮点数
      case Kfloat:
      case Knumber:
      case Kdouble: {
        // 从Lua栈获取数值，根据格式将其打包
        float f = (float)luaL_checknumber(L, arg);
        char *buff = luaL_prepbuffsize(&b, sizeof(f));
        copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
        luaL_addsize(&b, size);
        break;
      }
      case Kchar: {  /* 打包固定长度的字符串 */
        size_t len;
        const char *s = luaL_checklstring(L, arg, &len);
        luaL_argcheck(L, len <= (size_t)size, arg,
                         "字符串长度超过给定大小string longer than given size");
        luaL_addlstring(&b, s, len);  /* 添加字符串 */
        while (len++ < (size_t)size)  /* 对齐填充 */
          luaL_addchar(&b, LUAL_PACKPADBYTE);
        break;
      }
      case Kstring: {  /* 打包带长度计数的字符串 */
        size_t len;
        const char *s = luaL_checklstring(L, arg, &len);
        luaL_argcheck(L, size >= (int)sizeof(size_t) ||
                         len < ((size_t)1 << (size * NB)),
                         arg, "字符串长度不适合给定的大小string length does not fit in given size");
        packint(&b, (lua_Unsigned)len, h.islittle, size, 0);  /* 打包字符串长度 */
        luaL_addlstring(&b, s, len);
        totalsize += len;
        break;
      }
      case Kzstr: {  /* 打包以零结尾的字符串 */
        size_t len;
        const char *s = luaL_checklstring(L, arg, &len);
        luaL_argcheck(L, strlen(s) == len, arg, "字符串包含零string contains zeros");
        luaL_addlstring(&b, s, len);
        luaL_addchar(&b, '\0');  /* 添加结束符 */
        totalsize += len + 1;
        break;
      }
      case Kpadding: // 仅对齐填充，不处理参数
      case Kpaddalign: case Knop:
        arg--;  /* 不处理参数，回退参数计数 */
        break;
    }
  }
  luaL_pushresult(&b); // 将结果压入Lua栈
  return 1;
}


/*
 * 计算给定格式字符串所生成数据的大小。
 * 
 * 参数:
 *   L - Lua状态机，用于访问传入的参数和返回结果。
 * 
 * 返回值:
 *   返回1，将计算得到的数据大小作为整数压入Lua栈中。
 */

static int str_packsize (lua_State *L) {
  Header h; // 定义一个头部结构体变量，用于存储格式化过程中的信息。
  const char *fmt = luaL_checkstring(L, 1);  /* 格式字符串 */
  size_t totalsize = 0;  /* 用于累加结果数据的总大小 */
  initheader(L, &h); // 初始化头部结构体。

  // 遍历格式字符串，计算每种格式所占空间，并累加到totalsize中。
  while (*fmt != '\0') {
    int size, ntoalign;
    KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
    // 检查是否使用了不支持的可变长度格式。
    luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1,
                     "可变长度格式variable-length format");
    size += ntoalign;  /* 计算该选项占用的总空间 */
    // 检查结果是否过大，超过了允许的最大大小。
    luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
                     "格式化结果太大format result too large");
    totalsize += size; // 累加到总大小中
  }
  // 将计算得到的总大小作为整数压入Lua栈中。
  lua_pushinteger(L, (lua_Integer)totalsize);
  return 1; // 返回1，表示函数成功执行，并将1个结果压入了Lua栈。
}

/*
** 解包一个具有'size'字节和'islittle'字节序的整数。
** 如果'size'小于Lua整数的大小且整数为有符号的，必须进行符号扩展（将符号扩展到高位）；
** 如果'size'大于Lua整数的大小，则必须检查未读取的字节，以确保它们不会导致溢出。
*/
static lua_Integer unpackint (lua_State *L, const char *str,
                              int islittle, int size, int issigned) {
  lua_Unsigned res = 0; /* 用于存储解包后的无符号整数结果 */
  int i;
  int limit = (size  <= SZINT) ? size : SZINT; /* 确定需要处理的字节限制 */
  /* 循环处理每个字节，构建结果 */
  for (i = limit - 1; i >= 0; i--) {
    res <<= NB; /* 左移，为下一个字节腾出空间 */
    res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; /* 逻辑或操作，将字节加入结果 */
  }
  /* 处理'size'小于SZINT的情况，即实际大小小于Lua整数大小 */
  if (size < SZINT) {  
    if (issigned) { /* 需要进行符号扩展吗？ */
      lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); /* 创建掩码，用于符号扩展 */
      res = ((res ^ mask) - mask);  /* 执行符号扩展 */
    }
  }
  /* 处理'size'大于SZINT的情况，即必须检查未读取的字节 */
  else if (size > SZINT) {  
    int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; /* 根据是否为有符号以及结果的符号决定掩码值 */
    /* 检查未读取的字节，确保它们不会导致溢出 */
    for (i = limit; i < size; i++) {
      if (l_unlikely((unsigned char)str[islittle ? i : size - 1 - i] != mask))
        luaL_error(L, "%d-字节整数不适合存储在Lua整数中byte integer does not fit into Lua Integer", size);
    }
  }
  return (lua_Integer)res; /* 将结果转换为lua_Integer类型并返回 */
}

static int str_unpack (lua_State *L) {
  /*
 * 使用给定的格式字符串和数据字符串来解包数据，并将解包的结果压入Lua栈中。
 * 参数:
 *   L: Lua状态机的指针。
 *   fmt: 一个格式字符串，用于指定如何解包数据。
 *   data: 要解包的数据字符串。
 * 返回值:
 *   压入Lua栈中的结果的数量。
 */
Header h;
const char *fmt = luaL_checkstring(L, 1); // 检查并获取第一个Lua参数（格式字符串）。
size_t ld;
const char *data = luaL_checklstring(L, 2, &ld); // 检查并获取第二个Lua参数（数据字符串）及其长度。
size_t pos = posrelatI(luaL_optinteger(L, 3, 1), ld) - 1; // 计算起始解包位置。
int n = 0;  /* number of results */
luaL_argcheck(L, pos <= ld, 3, "数据字符串太短initial position out of string"); // 检查起始位置是否合法。
initheader(L, &h); // 初始化解包头信息。
while (*fmt != '\0') { // 遍历格式字符串，进行解包。
  int size, ntoalign;
  KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); // 获取当前格式字符的详细信息。
  luaL_argcheck(L, (size_t)ntoalign + size <= ld - pos, 2, "数据字符串太短data string too short"); // 检查数据长度是否足够。
  pos += ntoalign;  /* skip alignment */ // 跳过对齐部分。
  luaL_checkstack(L, 2, "结果太多too many results"); // 检查Lua栈空间是否足够。
  n++; // 结果计数器加一。
  switch (opt) { // 根据不同的格式选项解包数据。
    case Kint:
    case Kuint: {
      lua_Integer res = unpackint(L, data + pos, h.islittle, size, (opt == Kint));
      lua_pushinteger(L, res);
      break;
    }
    case Kfloat: {
      float f;
      copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
      lua_pushnumber(L, (lua_Number)f);
      break;
    }
    case Knumber: {
      lua_Number f;
      copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
      lua_pushnumber(L, f);
      break;
    }
    case Kdouble: {
      double f;
      copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
      lua_pushnumber(L, (lua_Number)f);
      break;
    }
    case Kchar: {
      lua_pushlstring(L, data + pos, size);
      break;
    }
    case Kstring: {
      size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);
      luaL_argcheck(L, len <= ld - pos - size, 2, "数据字符串太短data string too short");
      lua_pushlstring(L, data + pos + size, len);
      pos += len;  /* skip string */
      break;
    }
    case Kzstr: {
      size_t len = strlen(data + pos);
      luaL_argcheck(L, pos + len < ld, 2, "格式化字符串未完成unfinished string for format 'z'");
      lua_pushlstring(L, data + pos, len);
      pos += len + 1;  /* skip string plus final '\0' */
      break;
    }
    case Kpaddalign: case Kpadding: case Knop:
      n--;  /* undo increment */
      break;
  }
  pos += size; // 更新解包位置。
}
lua_pushinteger(L, pos + 1);  /* next position */
return n + 1; // 返回结果数量。
}

/* }====================================================== */


/* strlib 结构体定义了字符串库中所有函数的映射关系 */
static const luaL_Reg strlib[] = {
  {"byte", str_byte}, /* byte函数用于提取字符串中的一个或多个字节 */
  {"char", str_char}, /* char函数根据给定的数值创建一个字符串 */
  {"dump", str_dump}, /* dump函数将函数转换为二进制字符串 */
  {"find", str_find}, /* find函数在字符串中查找子字符串 */
  {"format", str_format}, /* format函数根据指定的格式创建一个字符串 */
  {"gmatch", gmatch}, /* gmatch函数返回一个迭代器，用于在字符串中进行全局正则表达式匹配 */
  {"gsub", str_gsub}, /* gsub函数在字符串中替换所有匹配的子串 */
  {"len", str_len}, /* len函数返回字符串的长度 */
  {"lower", str_lower}, /* lower函数将字符串中的大写字母转换为小写字母 */
  {"match", str_match}, /* match函数在字符串中进行模式匹配 */
  {"rep", str_rep}, /* rep函数重复字符串一定次数 */
  {"reverse", str_reverse}, /* reverse函数反转字符串 */
  {"sub", str_sub}, /* sub函数提取字符串的子串 */
  {"upper", str_upper}, /* upper函数将字符串中的小写字母转换为大写字母 */
  {"pack", str_pack}, /* pack函数将数据打包成二进制格式 */
  {"packsize", str_packsize}, /* packsize函数返回给定格式数据打包后的大小 */
  {"unpack", str_unpack}, /* unpack函数从二进制字符串中解包数据 */
/* 中文注释部分为对应的中文函数名，便于中文用户理解 */
  {"字节", str_byte},
  {"字符", str_char},
  {"转储", str_dump},
  {"查找", str_find},
  {"格式", str_format},
  {"匹配", gmatch},
  {"替换", str_gsub},
  {"长度", str_len},
  {"小写", str_lower},
  {"配对", str_match},
  {"重复", str_rep},
  {"倒序", str_reverse},
  {"子串", str_sub},
  {"大写", str_upper},
  {"打包", str_pack},
  {"包尺寸", str_packsize},
  {"拆包", str_unpack},
  {NULL, NULL} /* 结束标志 */
};

/* 创建字符串库的元表 */
/* 参数：
 * L: Lua状态机，用于操作Lua的全局表和栈
 */
static void createmetatable (lua_State *L) {
  /* 创建一个新表，作为字符串的元表 */
  luaL_newlibtable(L, stringmetamethods);
  luaL_setfuncs(L, stringmetamethods, 0);
  
  /* 创建一个空字符串，它将关联到元表 */
  lua_pushliteral(L, "");  
  /* 复制栈顶的表（元表）到栈顶，为设置元表做准备 */
  lua_pushvalue(L, -2);  
  /* 将栈顶的表设置为栈顶字符串的元表 */
  lua_setmetatable(L, -2);  
  
  /* 移除栈顶的空字符串 */
  lua_pop(L, 1);   
  /* 获取栈中之前的元表，并将其设置为字符串库的__index */
  lua_pushvalue(L, -2);  
  lua_setfield(L, -2, "__index");  
  
  /* 移除栈顶的元表 */
  lua_pop(L, 1); 
}

/*
** 打开字符串库
** 该函数在给定的 Lua 状态机中初始化并注册字符串库。
** 参数:
** L - 指向将要注册字符串库的 Lua 状态机的指针。
** 返回值:
** 返回 1，表示此函数推送到堆栈上的项目数量。
*/
LUAMOD_API int luaopen_string (lua_State *L) {
  // 创建一个新的字符串库表，并将其推送到堆栈上。
  luaL_newlib(L, strlib);

  // 创建并设置字符串库的元表。
  createmetatable(L);

  // 返回 1，因为该函数将一个项目（库表）推送到堆栈上。
  return 1;
}


